package com.john.blockchain.demo.first;

import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * @author jiangguangtao 2018/4/14
 */
public class HashCalcTask implements Runnable {
    private static final Logger LOGGER = LoggerFactory.getLogger(HashCalcTask.class);

    private HashCalcTaskContext taskContext;

    public HashCalcTask(HashCalcTaskContext taskContext) {
        this.taskContext = taskContext;
    }

    @Override
    public void run() {
        BlockingQueue<String> nonceQueue = taskContext.getNonceQueue();
        final String originString = taskContext.getOriginString();
        final String findCode = taskContext.getFindCode();
        final String halfFindCode = taskContext.getHalfFindCode();
        final CountDownLatch latch = taskContext.getLatch();
        int failFetchTimes = 0;
        while (taskContext.isTaskRunning()) {
            if (failFetchTimes > 5) {
                LOGGER.warn("5次取数失败，认识计算已经结束！");
                break;
            }

            try {
                String nonce = nonceQueue.poll(1, TimeUnit.SECONDS);
                if (null == nonce) {
                    failFetchTimes++;
                    continue;
                } else {
                    failFetchTimes = 0;
                }

                Long idx = taskContext.getNextCalcTimes();
                String hash = DigestUtils.sha256Hex(originString + nonce);
                if (hash.startsWith(findCode)) {
                    LOGGER.info("找到结果，使用的nonce字符串是：{}", nonce);
                    taskContext.finishTask(hash);
                    break;
                }

                if (hash.startsWith(halfFindCode)) {
                    LOGGER.info("{} 半发现一个 {} --nonce:{}", idx, hash, nonce);
                }

            } catch (InterruptedException e) {
                LOGGER.warn("计算线程出现中断异常 {}", e.getMessage());
            }
        }
        latch.countDown();
    }
}
